<?php

namespace dengje\workerman\process\httpServer;

use think\App;
use think\exception\Handle;
use think\exception\HttpException;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;

class Application extends App
{
	private string $serverName = '';

	/**
	 * 处理Worker请求
	 * @param TcpConnection $connection
	 * @param Request       $request
	 * @return void
	 */
	public function worker(TcpConnection $connection, Request $request): void
	{
		try {

			$this->beginTime = microtime(true);
			$this->beginMem  = memory_get_usage();
			$this->db->clearQueryTimes();

			$this->makeGlobal($connection, $request);

			// 解决第二次刷新识别应用不正确的bug
			$this->http->name('');

			// 逻辑处理 START =====================================================
			while (ob_get_level() > 1) {
				ob_end_clean();
			}

			ob_start();

			$response = $this->http->run();
			$content  = ob_get_clean();

			ob_start();

			$response->send();
			$this->http->end($response);

			$content .= ob_get_clean() ?: '';
			// 逻辑处理 END =====================================================

			$header = [
				'Server' => $this->serverName
			];
			foreach ($response->getHeader() as $name => $val) {
				$header[$name] = !is_null($val) ? $val : '';
			}

			$keepAlive = $request->header('connection');
			if (
				($keepAlive === null && $request->protocolVersion() === '1.1') ||
				strtolower($keepAlive) === 'keep-alive'
			) {
				$connection->send(
					$this->workermanResponse
						->withStatus($response->getCode())
						->withHeaders($header)
						->withBody($content)
				);
			} else {
				$connection->close($content);
			}

		} catch (HttpException|\Exception|\Throwable $e) {
			$this->exception($connection, $e);
		}
	}

	/**
	 * 是否运行在命令行下
	 * @return bool
	 */
	public function runningInConsole(): bool
	{
		return false;
	}

	public function setServerName($name)
	{
		$this->serverName = $name;
	}

	/**
	 * 错误信息发送给前端
	 * @param TcpConnection $connection
	 * @param               $e
	 * @return void
	 */
	protected function exception(TcpConnection $connection, $e): void
	{
		$response = function ($code, $content) {
			return $this->workermanResponse
				->withStatus($code)
				->withHeaders([
					'Server' => $this->serverName
				])
				->withBody($content);
		};

		if ($e instanceof \Exception) {
			$handler = $this->make(Handle::class);
			$handler->report($e);

			$resp    = $handler->render($this->request, $e);
			$content = $resp->getContent();
			$code    = $resp->getCode();

			$connection->send($response($code, $content));
		} else {
			$connection->send($response(500, $e->getMessage()));
		}
	}

	/**
	 * 兼容PHP-FPM框架
	 * @param TcpConnection $connection
	 * @param Request       $request
	 * @return void
	 */
	protected function makeGlobal(TcpConnection $connection, Request $request): void
	{
		global $_GET, $_POST, $_COOKIE, $_REQUEST, $_FILES, $_SERVER;

		$_GET     = $request->get();
		$_POST    = $request->post();
		$_COOKIE  = $request->cookie();
		$_REQUEST = [...$_GET, ...$_POST, ...$_COOKIE];
		$_FILES   = $request->file();

		$_SERVER = [
			'QUERY_STRING'    => $request->queryString(),
			'REQUEST_METHOD'  => $request->method(),
			'REQUEST_URI'     => $request->uri(),
			'SERVER_PROTOCOL' => 'HTTP/' . $request->protocolVersion(),
			'SERVER_SOFTWARE' => $this->serverName,
			'SERVER_NAME'     => $request->host(true),
			'CONTENT_TYPE'    => $request->header('content-type'),
			'REMOTE_ADDR'     => $connection->getRemoteIp(),
			'REMOTE_PORT'     => $connection->getRemotePort(),
			'CONTENT_LENGTH'  => $request->header('content-length'),
			'REQUEST_TIME'    => time(),
		];

		foreach ($request->header() as $key => $val) {
			$_SERVER['HTTP_' . strtoupper($key)] = $val;
		}
	}
}